#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
GitLab用户信息收集脚本

功能：
- 连接到指定的GitLab服务器
- 获取所有用户的详细信息
- 导出为CSV和JSON格式

使用方法：
python gitlab_users_collector.py
"""

import csv
import json
import os
from datetime import datetime
from typing import List, Dict, Optional

import requests
from loguru import logger


class GitLabUsersCollector:
    """GitLab用户信息收集器"""

    def __init__(self, gitlab_url: str, access_token: str):
        """
        初始化GitLab用户收集器
        
        Args:
            gitlab_url: GitLab服务器地址
            access_token: GitLab访问令牌
        """
        self.gitlab_url = gitlab_url.rstrip('/')
        self.access_token = access_token
        self.headers = {
            'Private-Token': access_token,
            'Content-Type': 'application/json'
        }

        # 配置日志
        logger.add(
            f"gitlab_users_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log",
            rotation="10 MB",
            retention="7 days",
            level="INFO"
        )

    def test_connection(self) -> bool:
        """
        测试GitLab连接
        
        Returns:
            bool: 连接是否成功
        """
        try:
            url = f"{self.gitlab_url}/api/v4/user"
            response = requests.get(url, headers=self.headers, timeout=10)

            if response.status_code == 200:
                user_info = response.json()
                is_admin = user_info.get('is_admin', False)
                logger.info(
                    f"连接成功！当前用户: {user_info.get('name', 'Unknown')} ({user_info.get('username', 'Unknown')})")
                logger.info(f"管理员权限: {'是' if is_admin else '否'}")

                if not is_admin:
                    logger.warning("当前访问令牌没有管理员权限，可能无法获取用户的私有邮箱地址")
                    logger.info("建议使用管理员账户的访问令牌以获取完整的用户信息")

                return True
            else:
                logger.error(f"连接失败，状态码: {response.status_code}, 响应: {response.text}")
                return False

        except Exception as e:
            logger.error(f"连接测试异常: {str(e)}")
            return False

    def check_admin_privileges(self) -> bool:
        """
        检查当前访问令牌是否具有管理员权限
        
        Returns:
            bool: 是否具有管理员权限
        """
        try:
            url = f"{self.gitlab_url}/api/v4/user"
            response = requests.get(url, headers=self.headers, timeout=10)

            if response.status_code == 200:
                user_info = response.json()
                return user_info.get('is_admin', False)
            else:
                return False

        except Exception as e:
            logger.error(f"检查管理员权限异常: {str(e)}")
            return False

    def get_all_users(self) -> List[Dict]:
        """
        获取所有用户信息
        
        Returns:
            List[Dict]: 用户信息列表
        """
        all_users = []
        page = 1
        per_page = 100  # 每页获取100个用户

        logger.info("开始获取用户列表...")

        while True:
            try:
                url = f"{self.gitlab_url}/api/v4/users"
                params = {
                    'page': page,
                    'per_page': per_page,
                    'active': True  # 只获取活跃用户
                }

                logger.info(f"正在获取第 {page} 页用户数据...")
                response = requests.get(url, headers=self.headers, params=params, timeout=30)

                if response.status_code != 200:
                    logger.error(f"获取用户列表失败，状态码: {response.status_code}, 响应: {response.text}")
                    break

                users = response.json()

                if not users:  # 没有更多用户了
                    logger.info("已获取所有用户数据")
                    break

                # 获取每个用户的详细信息
                for user in users:
                    detailed_user = self.get_user_details(user['id'])
                    if detailed_user:
                        all_users.append(detailed_user)

                logger.info(f"第 {page} 页获取到 {len(users)} 个用户，累计 {len(all_users)} 个用户")
                page += 1

            except Exception as e:
                logger.error(f"获取用户列表异常: {str(e)}")
                break

        logger.info(f"总共获取到 {len(all_users)} 个用户")
        return all_users

    def get_user_details(self, user_id: int) -> Optional[Dict]:
        """
        获取用户详细信息
        
        Args:
            user_id: 用户ID
            
        Returns:
            Optional[Dict]: 用户详细信息
        """
        try:
            url = f"{self.gitlab_url}/api/v4/users/{user_id}"
            response = requests.get(url, headers=self.headers, timeout=10)

            if response.status_code == 200:
                user_data = response.json()

                # 提取关键信息
                # 注意：email字段只有管理员权限才能访问，普通用户只能看到public_email
                email = user_data.get('email')  # 管理员可见
                public_email = user_data.get('public_email')  # 公开邮箱

                # 优先使用public_email，如果为空则尝试email字段
                final_email = public_email if public_email else email

                user_info = {
                    'id': user_data.get('id'),
                    'username': user_data.get('username'),
                    'name': user_data.get('name'),
                    'email': final_email,  # 使用处理后的邮箱
                    'public_email': public_email,  # 保留原始public_email字段
                    'private_email': email,  # 保留原始email字段（可能为空）
                    'state': user_data.get('state'),
                    'avatar_url': user_data.get('avatar_url'),
                    'web_url': user_data.get('web_url'),
                    'created_at': user_data.get('created_at'),
                    'last_sign_in_at': user_data.get('last_sign_in_at'),
                    'last_activity_on': user_data.get('last_activity_on'),
                    'bio': user_data.get('bio'),
                    'location': user_data.get('location'),
                    'skype': user_data.get('skype'),
                    'linkedin': user_data.get('linkedin'),
                    'twitter': user_data.get('twitter'),
                    'website_url': user_data.get('website_url'),
                    'organization': user_data.get('organization'),
                    'job_title': user_data.get('job_title'),
                    'projects_limit': user_data.get('projects_limit'),
                    'can_create_group': user_data.get('can_create_group'),
                    'can_create_project': user_data.get('can_create_project'),
                    'two_factor_enabled': user_data.get('two_factor_enabled'),
                    'external': user_data.get('external'),
                    'private_profile': user_data.get('private_profile')
                }

                return user_info
            else:
                logger.warning(f"获取用户 {user_id} 详细信息失败，状态码: {response.status_code}")
                return None

        except Exception as e:
            logger.error(f"获取用户 {user_id} 详细信息异常: {str(e)}")
            return None

    def export_to_csv(self, users: List[Dict], filename: str = None) -> str:
        """
        导出用户信息到CSV文件
        
        Args:
            users: 用户信息列表
            filename: 文件名（可选）
            
        Returns:
            str: 导出的文件路径
        """
        if not filename:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"gitlab_users_{timestamp}.csv"

        if not users:
            logger.warning("没有用户数据可导出")
            return filename

        # 获取所有字段名
        fieldnames = list(users[0].keys())

        try:
            with open(filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                writer.writerows(users)

            logger.info(f"用户信息已导出到CSV文件: {filename}")
            return filename

        except Exception as e:
            logger.error(f"导出CSV文件失败: {str(e)}")
            return filename

    def export_to_json(self, users: List[Dict], filename: str = None) -> str:
        """
        导出用户信息到JSON文件
        
        Args:
            users: 用户信息列表
            filename: 文件名（可选）
            
        Returns:
            str: 导出的文件路径
        """
        if not filename:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"gitlab_users_{timestamp}.json"

        try:
            export_data = {
                'export_time': datetime.now().isoformat(),
                'gitlab_url': self.gitlab_url,
                'total_users': len(users),
                'users': users
            }

            with open(filename, 'w', encoding='utf-8') as jsonfile:
                json.dump(export_data, jsonfile, ensure_ascii=False, indent=2)

            logger.info(f"用户信息已导出到JSON文件: {filename}")
            return filename

        except Exception as e:
            logger.error(f"导出JSON文件失败: {str(e)}")
            return filename

    def print_user_summary(self, users: List[Dict]):
        """
        打印用户统计摘要
        
        Args:
            users: 用户信息列表
        """
        if not users:
            logger.warning("没有用户数据")
            return

        logger.info(f"\n=== GitLab用户统计摘要 ===")
        logger.info(f"GitLab服务器: {self.gitlab_url}")
        logger.info(f"总用户数: {len(users)}")

        # 统计活跃用户
        active_users = [u for u in users if u.get('state') == 'active']
        logger.info(f"活跃用户数: {len(active_users)}")

        # 统计有邮箱的用户
        users_with_email = [u for u in users if u.get('email')]
        logger.info(f"有邮箱用户数: {len(users_with_email)}")

        # 统计外部用户
        external_users = [u for u in users if u.get('external')]
        logger.info(f"外部用户数: {len(external_users)}")

        logger.info(f"\n=== 前10个用户示例 ===")
        for i, user in enumerate(users[:10]):
            logger.info(
                f"{i + 1:2d}. {user.get('name', 'N/A'):20s} ({user.get('username', 'N/A'):15s}) - {user.get('email', 'N/A')}")

        if len(users) > 10:
            logger.info(f"... 还有 {len(users) - 10} 个用户")


def main():
    """
    主函数
    """
    # GitLab配置 - 从环境变量读取
    GITLAB_URL = os.getenv('GITLAB_URL', "http://10.10.50.201/")
    ACCESS_TOKEN = os.getenv('GITLAB_ACCESS_TOKEN', "EJAoCB5GWTaLYrhspXhC")  # 从环境变量读取Token

    logger.info("=== GitLab用户信息收集工具 ===")
    logger.info(f"目标服务器: {GITLAB_URL}")
    logger.info(f"访问令牌: {ACCESS_TOKEN[:8]}...")

    # 创建收集器实例
    collector = GitLabUsersCollector(GITLAB_URL, ACCESS_TOKEN)

    # 测试连接
    logger.info("正在测试GitLab连接...")
    if not collector.test_connection():
        logger.error("❌ GitLab连接失败，请检查URL和访问令牌")
        return

    logger.info("✅ GitLab连接成功！")

    # 获取所有用户
    logger.info("正在获取用户信息...")
    users = collector.get_all_users()

    if not users:
        logger.error("❌ 未获取到任何用户信息")
        return

    # 打印统计摘要
    collector.print_user_summary(users)

    # 检查管理员权限并给出邮箱字段说明
    is_admin = collector.check_admin_privileges()
    logger.info(f"\n📧 邮箱字段说明:")
    if is_admin:
        logger.info("✅ 当前具有管理员权限，可以获取用户的私有邮箱地址")
        logger.info("   - email: 用户的主要邮箱（私有或公开）")
        logger.info("   - public_email: 用户设置的公开邮箱")
        logger.info("   - private_email: 用户的私有邮箱（仅管理员可见）")
    else:
        logger.warning("⚠️  当前没有管理员权限，只能获取用户的公开邮箱")
        logger.info("   - email: 用户设置的公开邮箱（如果用户未设置公开邮箱则为空）")
        logger.info("   - public_email: 用户设置的公开邮箱")
        logger.info("   - private_email: 空（需要管理员权限）")
        logger.info("   💡 建议使用管理员账户的访问令牌以获取完整的邮箱信息")

    # 导出CSV文件
    logger.info("\n正在导出CSV文件...")
    csv_file = collector.export_to_csv(users)

    logger.info(f"\n=== 导出完成 ===")
    logger.info(f"CSV文件: {csv_file}")
    logger.info(f"日志文件: gitlab_users_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")

    logger.info("\n✅ 用户信息收集完成！")


if __name__ == "__main__":
    main()
